package com.hmdp.DistributedLock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RedissonLockUtil implements ILock {
    private static final String LOCK_PREFIX = "lock:";
    private String LockKeyName; // 服务名称
    private final String LockValue = UUID.randomUUID().toString() + "_"; // 锁的UUID的默认值
    //使用redisson客户端实现分布式锁
    private RedissonClient redissonClient;

    public RedissonLockUtil(RedissonClient redissonClient, String lockKeyName) {
        this.redissonClient = redissonClient;
        this.LockKeyName = lockKeyName;
    }

    /**
     * 尝试获取锁，成功返回true，失败返回false
     *
     * @Param timeoutSeconds 锁持有的超时时间，单位：秒,过期自动释放锁
     * @Return boolean true：获取锁成功，false：获取锁失败
     */
    @Override
    public boolean tryLock(long timeoutSeconds) throws InterruptedException {
        RLock rLock = getrLock();
        //尝试获取锁
        //rLock.tryLock(1,10, TimeUnit.SECONDS);/*三个参数分别为:等待时间(等待期间会重试获取锁),锁的超时释放时间,时间单位*/
        //rLock.tryLock();//没有参数时参数默认值,0:不等待,获取失败直接false,-1:永久等待,除非手动释放锁,时间单位无效所以没有第三个参数
        boolean isSuccess = rLock.tryLock(timeoutSeconds, TimeUnit.SECONDS);//设置带有超时时间的锁,没有等待重试,失败直接返回false
        //return BooleanUtil.isTrue(isSuccess);//源代码同下
        return Boolean.TRUE.equals(isSuccess);//防止空指针异常,除了是true,其他都返回false,是null也返回false
    }

    private RLock getrLock() {
        //拼接锁的key
        String key = LOCK_PREFIX + LockKeyName;
        String value = LockValue + Thread.currentThread().getId();
        //获取redisson的可重入锁对象
        RLock rLock = redissonClient.getLock(key);//参数为锁的名称,这里指定锁的名称key
        return rLock;
    }

    /**
     * 释放锁
     * 使用UUID+线程ID的方式来标识锁(保证集群环境下唯一性)，释放锁时，需要判断锁是否被当前线程持有，只有持有锁的线程才能释放锁
     */

    @Override
    public void unlock() {
        RLock rLock = getrLock();//获取锁对象
        rLock.unlock();//释放锁
    }

}
